package main

import (
	"fmt"
	"math/rand"
	"sync"
	"time"

	"gorm.io/driver/mysql"
	"gorm.io/gorm"
)

const (
	dsn           = "gva:gvagva@tcp(127.0.0.1:3306)/gormtest?charset=utf8mb4&parseTime=True&loc=Local"
	targetUserID  = 28        // 锁定用户ID必须为28
	targetName    = "郭威"      // 锁定用户名必须为"郭威"
	concurrency   = 1         // 并发请求数
	totalRequests = 100000000 // 总请求数
)

type UserTop struct {
	gorm.Model
	Name string `gorm:"unique"`
	Age  int8
	Hit  int64
}

func main() {
	// 初始化随机数种子
	rand.Seed(time.Now().UnixNano())

	// 连接数据库
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil {
		panic("连接数据库失败")
	}

	// 确保目标用户存在且信息正确
	var targetUser UserTop
	if err := db.First(&targetUser, targetUserID).Error; err != nil {
		// 如果用户不存在则创建
		targetUser = UserTop{
			Model: gorm.Model{ID: targetUserID},
			Name:  targetName, // 锁定名字
			Age:   28,
			Hit:   0,
		}
		if err := db.Create(&targetUser).Error; err != nil {
			panic("创建目标用户失败")
		}
	} else {
		// 验证现有用户信息
		if targetUser.Name != targetName {
			panic(fmt.Sprintf("用户ID %d 的名字不是'%s'", targetUserID, targetName))
		}
		if targetUser.ID != targetUserID {
			panic(fmt.Sprintf("用户ID不匹配，期望 %d 实际 %d", targetUserID, targetUser.ID))
		}
	}

	fmt.Printf("开始为锁定用户 %s(ID:%d) 刷点赞...\n", targetUser.Name, targetUser.ID)
	fmt.Printf("并发数: %d, 总请求数: %d\n", concurrency, totalRequests)

	// 使用WaitGroup等待所有goroutine完成
	var wg sync.WaitGroup
	wg.Add(concurrency)

	// 创建并发worker
	startTime := time.Now()
	for i := 0; i < concurrency; i++ {
		go func(workerID int) {
			defer wg.Done()

			// 每个worker发送的请求数
			requestsPerWorker := totalRequests / concurrency

			for j := 0; j < requestsPerWorker; j++ {
				// 每6次生成一个随机增量
				increment := 10
				if j%6 == 0 {
					increment = rand.Intn(100) + 1 // 生成1-100的随机数
				}

				// 直接更新数据库，同时验证用户ID和名字
				if err := db.Model(&UserTop{}).
					Where("id = ? AND name = ?", targetUserID, targetName). // 双重验证
					Update("Hit", gorm.Expr("Hit + ?", increment)).Error; err != nil {
					fmt.Printf("Worker %d: 第 %d 次点赞失败: %v\n", workerID, j+1, err)
					continue
				}

				// 打印进度(每10000次打印一次)
				if (j+1)%1000 == 0 {
					fmt.Printf("Worker %d: 已完成 %d/%d (本次增加: %d)\n",
						workerID, j+1, requestsPerWorker, increment)
				}
			}
		}(i)
	}

	// 等待所有worker完成
	wg.Wait()

	// 查询最终结果并再次验证
	var finalUser UserTop
	if err := db.First(&finalUser, targetUserID).Error; err != nil {
		panic("查询最终结果失败")
	}
	if finalUser.Name != targetName || finalUser.ID != targetUserID {
		panic("最终验证失败：用户信息不匹配")
	}

	elapsed := time.Since(startTime)
	fmt.Printf("\n刷点赞完成!\n")
	fmt.Printf("锁定用户: %s(ID:%d)\n", finalUser.Name, finalUser.ID)
	fmt.Printf("最终点赞数: %d\n", finalUser.Hit)
	fmt.Printf("总耗时: %v\n", elapsed)
	fmt.Printf("QPS: %.2f\n", float64(totalRequests)/elapsed.Seconds())
}
